package org.sxp.common.jwt;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.sxp.common.utils.Constant;
import org.sxp.common.utils.ShiroSessionTool;
import org.sxp.common.utils.SpringContextUtils;
import org.sxp.common.websocket.WebSocketSession;
import org.sxp.modules.sys.dao.SysMenuDao;
import org.sxp.modules.sys.dao.SysUserDao;
import org.sxp.modules.sys.entity.SysMenuEntity;
import org.sxp.modules.sys.entity.SysUserEntity;

import java.util.*;

/**
 * @author shenxingping
 * @date 2021/02/03
 */
@Component
public class JWTRealm extends AuthorizingRealm {

    @Autowired(required = false)
    private SysUserDao sysUserDao;
    @Autowired(required = false)
    private SysMenuDao sysMenuDao;


    /**
     * 一定需要创建,不然出错
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 权限认证
     * @author HCY
     * @since 2020-10-11
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SysUserEntity userEntity = (SysUserEntity)principalCollection.getPrimaryPrincipal();
        List<String> permsList;
        //系统管理员，拥有最高权限
        if(userEntity.getUserId() == Constant.SUPER_ADMIN){
            List<SysMenuEntity> menuList = sysMenuDao.selectList(null);
            permsList = new ArrayList<>(menuList.size());
            for(SysMenuEntity menu : menuList){
                permsList.add(menu.getPerms());
            }
        }else{
            permsList = sysUserDao.queryAllPerms(userEntity.getUserId());
        }
        //用户权限列表
        Set<String> permsSet = new HashSet<>();
        for(String perms : permsList){
            if(StringUtils.isBlank(perms)){
                continue;
            }
            permsSet.addAll(Arrays.asList(perms.trim().split(",")));
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 身份验证
     * @author HCY
     * @since 2020-10-11
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        try{
            if ( ! JwtUtlis.verify(token)){
                throw new AuthenticationException("token出现错误");
            }
        }catch (Exception e){
            throw new AuthenticationException("token出现错误");
        }
        //通过解密获得账号和密码
        String userId = JwtUtlis.getString(token,"userId");

        //查询用户信息
        SysUserEntity user = sysUserDao.selectOne(
                new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getUserId, Long.parseLong(userId))
        );
        //账号不存在
        if(user == null) {
            throw new UnknownAccountException("账号不存在");
        }
        //账号锁定
        if(user.getStatus() == 0){
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        ShiroSessionTool shiroSessionTool = SpringContextUtils.getBean(ShiroSessionTool.class);
        //以下为只允许同一账户单个登录
        Collection<Session> sessions = shiroSessionTool.sessionList();
        if(sessions.size()>0) {
            for (Session session : sessions) {
                if (session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) {
                    continue;
                } else {
                    SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) session
                            .getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
                    SysUserEntity userDO = (SysUserEntity) principalCollection.getPrimaryPrincipal();
                    //获得session中已经登录用户的名字
                    if (userDO.getUsername().equals(user.getUsername())) {  //这里的username也就是当前登录的username
                        WebSocketSession.convertAndSendToUser(userDO.getUserId().toString(), "/queue/loginOut", "异地登录，当前用户下线");
                        shiroSessionTool.delete(session);
                        break;
                    }
                }
            }
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, token, getName());
        return info;

    }
}
